package com.tiancheng.trade.settlement.service.settlement.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.settlement.enums.OrderSourceEnum;
import com.tiancheng.trade.settlement.enums.PaymentChannelEnum;
import com.tiancheng.trade.settlement.mapper.settlement.BankrollClearingDataMapper;
import com.tiancheng.trade.settlement.mapper.settlement.BankrollClearingMapper;
import com.tiancheng.trade.settlement.mapper.settlement.BankrollClearingVerifiedMapper;
import com.tiancheng.trade.settlement.model.settlement.BankrollClearing;
import com.tiancheng.trade.settlement.model.settlement.BankrollClearingData;
import com.tiancheng.trade.settlement.model.settlement.BankrollClearingVerified;
import com.tiancheng.trade.settlement.service.settlement.ISelfSupportSettlementService;
import com.tiancheng.trade.settlement.util.ExcelUtil;
import com.tiancheng.trade.settlement.util.JacksonJsonUtil;
import com.tiancheng.trade.settlement.util.ObjectConvertUtil;
import com.tiancheng.trade.settlement.vo.settlement.admin.*;
import com.tiancheng.trade.settlement.vo.settlement.export.NoSettlementOrderExportVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class SelfSupportSettlementService implements ISelfSupportSettlementService {
    @Autowired
    BankrollClearingDataMapper bankrollClearingDataMapper;
    @Autowired
    BankrollClearingMapper bankrollClearingMapper;
    @Autowired
    BankrollClearingVerifiedMapper bankrollClearingVerifiedMapper;
    private final String format = "yyyy-MM-dd";
    @Autowired
    private ObjectMapper objectMapper;
    @Resource
    private JacksonJsonUtil jacksonJsonUtil;

    @Override
    public Map<String, Object> query(SelfSupportSettlementVO vo) {
        Map<String, Object> dataMap = new HashMap<>();
        if (StringUtils.isEmpty(vo.getYearMonth())) {
            return dataMap;
        }
        try {
            SelfSupportSettlementResultOneVO oneVo = rtnQueryOne(vo);
            SelfSupportSettlementResultTwoVO twoVo = rtnQueryTwo(vo);
            List<SelfSupportSettlementResultThreeVO> threeVos = rtnQueryThree(vo);
            if (null == oneVo && null == twoVo && CollectionUtils.isEmpty(threeVos)) {
                return dataMap;
            }
            if (null != oneVo) {
                dataMap.put("statistics_time", oneVo.getStatisticsTime());
                dataMap.put("generation_time", oneVo.getGenerationTime());
            }
            dataMap.put("one", oneVo);
            dataMap.put("two", twoVo);
            SelfSupportSettlementResultThreeTotalVO totalVo = get(threeVos);
            dataMap.put("three", totalVo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataMap;
    }

    private SelfSupportSettlementResultThreeTotalVO get(List<SelfSupportSettlementResultThreeVO> threeVos) {
        Integer settlementAmount = 0;
        Integer serviceCharge = 0;
        Integer factSettlementAmount = 0;
        Integer notSettlementAmount = 0;
        for (SelfSupportSettlementResultThreeVO tvo : threeVos) {
            settlementAmount += tvo.getSettlementAmount() == null ? 0 : tvo.getSettlementAmount();
            serviceCharge += tvo.getServiceCharge() == null ? 0 : tvo.getServiceCharge();
            factSettlementAmount += tvo.getFactSettlementAmount() == null ? 0 : tvo.getFactSettlementAmount();
            notSettlementAmount += tvo.getNotSettlementAmount() == null ? 0 : tvo.getNotSettlementAmount();
        }
        SelfSupportSettlementResultThreeTotalVO totalVo = new SelfSupportSettlementResultThreeTotalVO();
        totalVo.setThreeTotal(threeVos);
        totalVo.setSettlementAmountTotal(settlementAmount);
        totalVo.setServiceChargeTotal(serviceCharge);
        totalVo.setFactSettlementAmountTotal(factSettlementAmount);
        totalVo.setNotSettlementAmountTotal(notSettlementAmount);
        return totalVo;
    }

    @Override
    public Map<String, Object> update(SelfSupportSettlementVO vo) {
        Map<String, Object> dataMap = new HashMap<>();
        if (StringUtils.isEmpty(vo.getYearMonth())) {
            return dataMap;
        }
        SelfSupportSettlementResultOneVO oneVo = updateOne(vo);
        SelfSupportSettlementResultTwoVO twoVo = updateTwo(vo);
        List<SelfSupportSettlementResultThreeVO> threesVo = updateThree(vo);
        if (null != oneVo) {
            dataMap.put("statistics_time", oneVo.getStatisticsTime());
            dataMap.put("generation_time", oneVo.getGenerationTime());
        }
        dataMap.put("one", oneVo);
        dataMap.put("two", twoVo);
        SelfSupportSettlementResultThreeTotalVO totalVo = get(threesVo);
        dataMap.put("three", totalVo);
        return dataMap;
    }

    /**
     * 更新第一块内容
     *
     * @param vo
     * @return
     */
    private SelfSupportSettlementResultOneVO updateOne(SelfSupportSettlementVO vo) {
        SelfSupportSettlementResultOneVO oneVo = bankrollClearingMapper.reportFormOne(vo);
        if (oneVo == null) {
            BankrollClearing one = queryBankrollClearing(vo.getYearMonth());
            oneVo = ObjectConvertUtil.convert(one, SelfSupportSettlementResultOneVO.class).get();
            return oneVo;
        }
        BankrollClearing one = queryBankrollClearing(vo.getYearMonth());
        oneVo.setStatisticsTime(one.getStatisticsTime());
        oneVo.setGenerationTime(DateTimeUtil.getSystemDate(format));
        one = ObjectConvertUtil.convert(oneVo, BankrollClearing.class).get();
        int count = bankrollClearingMapper.update(one);
        if (count > 0) {
            return oneVo;
        }
        return null;
    }

    /**
     * 更新第二块内容
     *
     * @param vo
     * @return
     */
    private SelfSupportSettlementResultTwoVO updateTwo(SelfSupportSettlementVO vo) {
        SelfSupportSettlementResultTwoVO twoVo = bankrollClearingVerifiedMapper.reportFormTwo(vo);
        if (twoVo == null) {
            BankrollClearingVerified two = queryBankrollClearingVerified(vo.getYearMonth());
            twoVo = ObjectConvertUtil.convert(two, SelfSupportSettlementResultTwoVO.class).get();
            return twoVo;
        }
        BankrollClearingVerified two = queryBankrollClearingVerified(vo.getYearMonth());
        two = ObjectConvertUtil.convert(twoVo, BankrollClearingVerified.class).get();
        two.setStatisticsTime(vo.getYearMonth());
        two.setGenerationTime(DateTimeUtil.getSystemDate(format));
        int count = bankrollClearingVerifiedMapper.update(two);
        if (count > 0) {
            return twoVo;
        }
        return null;
    }

    /**
     * 更新第三块内容
     *
     * @param vo
     * @return
     */
    private List<SelfSupportSettlementResultThreeVO> updateThree(SelfSupportSettlementVO vo) {
        List<SelfSupportSettlementResultThreeVO> threes = bankrollClearingDataMapper.reportFormThree(vo);
        if (threes == null || threes.isEmpty()) {
            List<BankrollClearingData> datas = queryBankrollClearingData(vo.getYearMonth());
            try {
                threes = objectMapper.readValue(jacksonJsonUtil.toJson(datas),
                        new TypeReference<List<SelfSupportSettlementResultThreeVO>>() {
                        });
                return threes;
            } catch (JsonMappingException e) {
                e.printStackTrace();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        List<BankrollClearingData> threesVo = new ArrayList<>();
        for (SelfSupportSettlementResultThreeVO tvo : threes) {
            QueryWrapper<BankrollClearingData> conditions = new QueryWrapper<>();
            conditions.eq("settlement_date", tvo.getSettlementDate());
            BankrollClearingData data = bankrollClearingDataMapper.selectOne(conditions);
            if (data == null) {
                data = new BankrollClearingData();
                data = ObjectConvertUtil.convert(tvo, BankrollClearingData.class).get();
                data.setStatisticsTime(vo.getYearMonth());
                data.setGenerationTime(DateTimeUtil.getSystemDate(format));
                threesVo.add(data);
            } else {
                data = ObjectConvertUtil.convert(tvo, BankrollClearingData.class).get();
                data.setGenerationTime(DateTimeUtil.getSystemDate(format));
                bankrollClearingDataMapper.update(data);
            }
        }
        if (!threesVo.isEmpty()) {
            bankrollClearingDataMapper.batchSave(threesVo);
        }
        return threes;
    }

    /**
     * 返回第一块数据内容
     *
     * @return
     */
    private SelfSupportSettlementResultOneVO rtnQueryOne(SelfSupportSettlementVO vo) {
        BankrollClearing one = queryBankrollClearing(vo.getYearMonth());
        SelfSupportSettlementResultOneVO oneVo = null;
        if (one == null) {
            one = new BankrollClearing();
            oneVo = bankrollClearingMapper.reportFormOne(vo);
            if (oneVo != null) {
                oneVo.setStatisticsTime(vo.getYearMonth());
                oneVo.setGenerationTime(DateTimeUtil.getSystemDate(format));
                one = ObjectConvertUtil.convert(oneVo, BankrollClearing.class).get();
                bankrollClearingMapper.insert(one);
            }
        } else {
            oneVo = ObjectConvertUtil.convert(one, SelfSupportSettlementResultOneVO.class).get();
        }
        return oneVo;
    }

    /**
     * 返回第二块数据内容
     *
     * @return
     */
    private SelfSupportSettlementResultTwoVO rtnQueryTwo(SelfSupportSettlementVO vo) {
        BankrollClearingVerified two = queryBankrollClearingVerified(vo.getYearMonth());
        SelfSupportSettlementResultTwoVO twoVo = null;
        if (two == null) {
            two = new BankrollClearingVerified();
            twoVo = bankrollClearingVerifiedMapper.reportFormTwo(vo);
            if (twoVo != null) {
                two = ObjectConvertUtil.convert(twoVo, BankrollClearingVerified.class).get();
                two.setStatisticsTime(vo.getYearMonth());
                two.setGenerationTime(DateTimeUtil.getSystemDate(format));
                bankrollClearingVerifiedMapper.insert(two);
            }
        } else {
            twoVo = ObjectConvertUtil.convert(two, SelfSupportSettlementResultTwoVO.class).get();
        }
        return twoVo;
    }

    /**
     * 返回第三块数据内容
     *
     * @return
     */
    private List<SelfSupportSettlementResultThreeVO> rtnQueryThree(SelfSupportSettlementVO vo) {
        List<BankrollClearingData> threes = queryBankrollClearingData(vo.getYearMonth());
        List<SelfSupportSettlementResultThreeVO> threeVOs = null;
        if (threes == null || threes.isEmpty()) {
            threeVOs = bankrollClearingDataMapper.reportFormThree(vo);
            if (threeVOs != null && !threeVOs.isEmpty()) {
                List<BankrollClearingData> dataResults = toBankrollClearingData(threeVOs);
                dataResults.stream().forEach(data -> {
                    data.setStatisticsTime(vo.getYearMonth());
                    data.setGenerationTime(DateTimeUtil.getSystemDate(format));
                });
                bankrollClearingDataMapper.batchSave(dataResults);
            }
        } else {
            threeVOs = toSelfSupportSettlementResultThreeVO(threes);
        }
        return threeVOs;
    }

    private List<BankrollClearingData> toBankrollClearingData(List<SelfSupportSettlementResultThreeVO> threeVOs) {
        List<BankrollClearingData> dataResults = new ArrayList<>();
        for (SelfSupportSettlementResultThreeVO data : threeVOs) {
            BankrollClearingData vo = ObjectConvertUtil.convert(data, BankrollClearingData.class).get();
            dataResults.add(vo);
        }
        return dataResults;
    }

    private List<SelfSupportSettlementResultThreeVO> toSelfSupportSettlementResultThreeVO(List<BankrollClearingData> threeVOs) {
        List<SelfSupportSettlementResultThreeVO> dataResults = new ArrayList<>();
        for (BankrollClearingData data : threeVOs) {
            SelfSupportSettlementResultThreeVO vo = ObjectConvertUtil.convert(data, SelfSupportSettlementResultThreeVO.class).get();
            dataResults.add(vo);
        }
        return dataResults;
    }

    /**
     * 查询第一块内容
     *
     * @param yearMonth
     * @return
     */
    private BankrollClearing queryBankrollClearing(String yearMonth) {
        QueryWrapper<BankrollClearing> conditions = new QueryWrapper<>();
        conditions.eq("statistics_time", yearMonth);
        return bankrollClearingMapper.selectOne(conditions);
    }

    /**
     * 查询第二块内容
     *
     * @param yearMonth
     * @return
     */
    private BankrollClearingVerified queryBankrollClearingVerified(String yearMonth) {
        QueryWrapper<BankrollClearingVerified> conditions = new QueryWrapper<>();
        conditions.eq("statistics_time", yearMonth);
        return bankrollClearingVerifiedMapper.selectOne(conditions);
    }

    /**
     * 查询第三块内容
     *
     * @param yearMonth
     * @return
     */
    private List<BankrollClearingData> queryBankrollClearingData(String yearMonth) {
        QueryWrapper<BankrollClearingData> conditions = new QueryWrapper<>();
        conditions.likeRight("settlement_date", yearMonth);
        return bankrollClearingDataMapper.selectList(conditions);
    }

    @Override
    public void noSettlementOrderExport(@Valid SelfSupportSettlementVO vo, HttpServletRequest request,
                                        HttpServletResponse response) {
        List<NoSettlementOrderExportVO> list = bankrollClearingDataMapper.noSettlementOrderExport(vo);
        if (CollectionUtils.isNotEmpty(list)) {
            BigDecimal bigNum1 = new BigDecimal(100);
            list.forEach(a -> {
                a.setOrderSource(OrderSourceEnum.getDesc(a.getOrderSource()));
                a.setPayChannelCode(PaymentChannelEnum.getDesc(a.getPayChannelCode()));
                if (StringUtils.isNotEmpty(a.getVerifiedAmount())) {
                    BigDecimal hotelRate = new BigDecimal(a.getVerifiedAmount());
                    a.setVerifiedAmount(hotelRate.divide(bigNum1).toString());
                }
            });
        }

        List<Map<String, Object>> mapList = listConvert(list);
        String date = DateTimeUtil.getSystemDate("yyyy-MM-dd");
        String fileName = "未清算金额订单明细" + date + ".xlsx";

        String[] title = {"主订单号", "子订单号",
                "渠道支付订单号", "商品编码", "商品名称",
                "业务场景", "商户名称", "商户编码", "清分渠道"
                , "清分金额", "交易时间", "核销时间"};
        Workbook workbook;
        try {
            workbook = ExcelUtil.buildWorkbook(fileName, title, mapList);
            ExcelUtil.exportExcle(request, response, workbook, fileName);
        } catch (IOException e) {
            log.info("导出差额明细数据出现异常{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 数据转换
     *
     * @param list
     * @return
     */
    private List<Map<String, Object>> listConvert(List<NoSettlementOrderExportVO> list) {
        List<Map<String, Object>> list_map = new ArrayList<Map<String, Object>>();
        try {
            for (NoSettlementOrderExportVO t : list) {
                Field[] fields = t.getClass().getDeclaredFields();
                Map<String, Object> m = new LinkedHashMap<String, Object>();
                for (Field field : fields) {
                    String keyName = field.getName();
                    PropertyDescriptor pd = new PropertyDescriptor(keyName, t.getClass());
                    Method getMethod = pd.getReadMethod();// 获得getter方法
                    Object o = getMethod.invoke(t);// 执行get方法返回一个Object
                    m.put(keyName, o);
                }
                list_map.add(m);
            }
            return list_map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
